﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

using LowLevelGraphics.ColorSpaces;

namespace LowLevelGraphics.Filter.Colors
{
    /// <summary>
    /// Replace one channel with another channel
    /// <see cref="Lambda"/>You might also to this using a lambda command</see>
    /// </summary>
    public class ReplaceChannel : BaseImageFilter
    {
        protected int m_nChannelIndex = 0;
        protected int m_nChannelIndexToReplaceTo = 0;

        /// <summary>
        /// Initializes a new instance of the <see cref="ReplaceChannel"/> class.
        /// </summary>
        public ReplaceChannel()
        {
            m_AbstractColorSpace = new YCbCr(Color.Transparent);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ReplaceChannel"/> class.
        /// </summary>
        /// <param name="_abstractColorSpace">The _abstract color space.</param>
        public ReplaceChannel(AbstractColorSpace _abstractColorSpace, int _nChannelIndex, int _nChannelIndexToReplaceTo)
        {
            m_AbstractColorSpace = _abstractColorSpace;
            m_nChannelIndex = _nChannelIndex;
            m_nChannelIndexToReplaceTo = _nChannelIndexToReplaceTo;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ReplaceChannel"/> class.
        /// </summary>
        /// <param name="_replaceChannel">The _replace channel.</param>
        internal ReplaceChannel(ReplaceChannel _replaceChannel)
        {
            this.m_AbstractColorSpace = _replaceChannel.m_AbstractColorSpace;
            this.m_nChannelIndex = _replaceChannel.m_nChannelIndex;
            this.m_nChannelIndexToReplaceTo = _replaceChannel.m_nChannelIndexToReplaceTo;
        }

        /// <summary>
        /// Gets or sets the index of the channel.
        /// </summary>
        /// <value>The index of the channel.</value>
        public int ChannelIndex
        {
            get { return m_nChannelIndex; }
            set { m_nChannelIndex = value; }
        }

        /// <summary>
        /// Gets or sets the channel index to replace to.
        /// </summary>
        /// <value>The channel index to replace to.</value>
        public int ChannelIndexToReplaceTo
        {
            get { return m_nChannelIndexToReplaceTo; }
            set { m_nChannelIndexToReplaceTo = value; }
        }

        /// <summary>
        /// Execute this Filter
        /// A Debug Statement is written if a concrete Filter is called
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            int nHeight = _bitmap.Height;
            int nWidth = _bitmap.Width;

            int y = 0;
            int x = 0;
            object[] aValue = null;
            AbstractColorSpace colorSpace = null;

            Color color = Color.Transparent;
            for (y = 0; y < nHeight; y++)
            {
                for (x = 0; x < nWidth; x++)
                {
                    color = _bitmap[x, y];
                    m_AbstractColorSpace.Color = color;
                    aValue = m_AbstractColorSpace.GetValues();
                    colorSpace = (AbstractColorSpace)Activator.CreateInstance(m_AbstractColorSpace.GetType(), new object[] { color });
                    aValue[m_nChannelIndexToReplaceTo] = aValue[m_nChannelIndex];
                    colorSpace.SetValues(aValue);
                    _bitmap[x, y] = colorSpace.ToColor();
                }
            }
            return _bitmap;
        }

        /// <summary>
        /// This is used to clone a filter, each filter must implement it's own clone functionality
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new ReplaceChannel(this);
        }
    }
}
